# 第一步，GY6600合并进账户模块-账户信息查询，选择使用正常使用点击查询后导出。
# 使用之前需要删除 旧版导出的文件
# HTML表格数据提取和Excel保存工具
# 专门用于从HTML表格中提取数据并保存为Excel文件
import json
import logging  # 导入日志模块
import os  # 导入操作系统模块
import re  # 导入正则表达式模块
import time  # 导入时间模块
from time import sleep  # 导入sleep函数

import pandas as pd  # 导入pandas处理Excel文件
import requests
from bs4 import BeautifulSoup
from selenium import webdriver  # 导入selenium webdriver
from selenium.webdriver.chrome.options import Options  # 导入Chrome选项
from selenium.webdriver.common.by import By  # 导入定位方式

# from pymupdf import fitz  # PyMuPDF

# # PDF处理相关库
# try:
#     import fitz  # PyMuPDF
#
#     PDF_LIBRARY_AVAILABLE = True
# except ImportError:

try:
    from PyPDF2 import PdfReader, PdfWriter

    PDF_LIBRARY_AVAILABLE = True
except ImportError:
    PDF_LIBRARY_AVAILABLE = False
    print("警告：未安装PDF处理库，请安装 PyMuPDF 或 PyPDF2")

from util import change_sk
from 重构版差异分析 import HTMLTableProcessor
from config import Config


# 配置日志
def setup_logger():
    """配置日志"""
    # 创建日志目录
    log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logs")
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)

    # 日志文件路径
    log_file = os.path.join(log_dir, f"ocr_diff_{time.strftime('%Y%m%d_%H%M%S')}.log")

    # 配置日志格式
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler(log_file, encoding='utf-8'),
            logging.StreamHandler()  # 同时输出到控制台
        ]
    )

    return logging.getLogger(__name__)


# 创建logger
logger = setup_logger()


def 导出():
    # 设置Chrome调试端口(注释状态)
    # chrome.exe --remote-debugging-port=9222 --user-data-dir="D:\selenium"

    # 设置下载目录
    # 获取当前脚本所在目录下的download文件夹路径
    download_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "download")
    # 获取下载前的文件列表(用于后续比较哪些是新下载的文件)
    before_download = set(os.listdir(download_dir))

    # 配置Chrome浏览器选项
    chrome_options = Options()
    driver_path = r'chromedriver.exe'  # ChromeDriver路径；指定ChromeDriver路径

    # 设置下载默认目录
    prefs = {"download.default_directory": os.path.join(os.path.dirname(os.path.abspath(__file__)), "download")}
    chrome_options.add_experimental_option('prefs', prefs)
    chrome_options.add_argument('--disable-gpu')  # 禁用GPU加速
    chrome_options.add_argument('--no-sandbox')  # 禁用沙盒模式

    # 设置Chrome浏览器路径
    # chrome_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Application", "chrome.exe")
    # chrome_options.binary_location = chrome_path

    # 初始化WebDriver
    driver = webdriver.Chrome(executable_path=driver_path, options=chrome_options)

    # 登录系统
    driver.get("http://tms.ceic.com/")  # 打开系统网址
    driver.maximize_window()  # 最大化窗口
    driver.implicitly_wait(20)  # 设置隐式等待时间

    # 登录循环(直到成功为止)
    while True:
        try:
            # 输入用户名和密码
            driver.find_element_by_xpath('//*[@id="username"]').send_keys("20034176")
            driver.find_element_by_xpath('//*[@id="password"]').send_keys("Wzr896*-+")
            driver.find_element_by_xpath('//*[@id="kc-submit"]').click()  # 点击登录按钮
            break  # 登录成功则退出循环
        except:
            time.sleep(5)  # 登录失败等待5秒后重试

    # 切换到指定公司
    change_sk(driver, 'GY6600')

    # 进入账户管理菜单
    while True:
        try:
            driver.find_element(By.XPATH, "//*[text()=' 账户管理 ']").click()  # 点击账户管理
            break
        except:
            time.sleep(2)  # 点击失败等待2秒后重试

    sleep(3)  # 等待3秒

    # 进入账户信息查询（多币种）
    driver.find_element(By.XPATH, "//*[text()='账户信息查询']").click()  # 还是导多币种出来

    sleep(10)  # 等待10秒

    # 切换到指定的iframe
    iframe = driver.find_element(By.XPATH,
                                 "//iframe[contains(@src, 'index.html')]")  # 注意这里外面有双引号的话，改为单引号，//iframe[contains(@src, "index.html")]
    driver.switch_to.frame(iframe)

    sleep(5)

    # 点击"使用状态"旁边的展开框
    driver.find_element(By.XPATH,
                        '//*[@id="layout_query"]/div/div[4]/div/div[3]/span[2]/span/span').click()

    sleep(2)

    # 勾选正常使用
    driver.find_element(By.XPATH, "/html/body/div[23]/div/div[1]").click()
    # /html/body/div[23]/div/div[1]

    sleep(2)

    # 点击查询
    driver.find_element(By.XPATH, "/html/body/div[1]/div[1]/div[3]/div[1]/div/div[1]/div[2]/a/span/span").click()

    sleep(10)  # 等待查询结果10秒

    # 导出数据
    driver.find_element(By.XPATH, "//*[@id='export']/span/span").click()

    sleep(5)  # 等待3秒

    driver.find_element(By.XPATH, "//*[@id='ok1']/span/span").click()  # 确认导出

    sleep(10)  # 等待10秒


def process_ocr_data(data):
    """
    处理OCR返回的表格数据，将按列组织的数据重新按行组织
    参数：
        data: OCR返回的JSON数据
    返回：
        rows: 按行组织的数据列表，每行是一个字典
    """
    form_data = data.get('form', [])

    # 确定行数
    if not form_data:
        logger.warning("OCR返回数据不包含表单信息")
        return []

    row_count = len(form_data[0].get('list', []))
    rows = []

    # 按行重组数据
    for row_idx in range(row_count):
        row_dict = {}
        for column in form_data:
            column_name = column.get('name', '')
            column_values = column.get('list', [])
            if row_idx < len(column_values):
                row_dict[column_name] = column_values[row_idx]
            else:
                row_dict[column_name] = ''
        rows.append(row_dict)

    logger.info(f"OCR原始数据处理完成，共 {len(rows)} 条记录")

    # 过滤无效账号
    filtered_rows = []
    for row in rows:
        account_number = row.get('账号', '')
        if is_valid_account_number(account_number):
            filtered_rows.append(row)
        else:
            logger.warning(f"剔除无效账号数据: {row}")

    logger.info(f"过滤后剩余 {len(filtered_rows)} 条有效记录，剔除 {len(rows) - len(filtered_rows)} 条无效记录")

    return filtered_rows


def normalize_bank_name(bank_name):
    """
    标准化银行名称，处理不同格式的银行名称
    参数：
        bank_name: 原始银行名称
    返回：
        标准化后的银行名称
    """
    if not bank_name:
        return ""

    # 转为字符串并去除前后空白
    bank_name = str(bank_name).strip()

    # 常见的银行名称后缀
    common_suffixes = [
        "股份有限公司",
        "有限责任公司",
        "股份公司",
        "有限公司"
    ]

    # 移除这些后缀
    for suffix in common_suffixes:
        bank_name = bank_name.replace(suffix, "")

    # 提取主要银行名称和分支机构名称
    # 主要银行名称通常在前面，分支机构名称通常在后面
    main_banks = [
        "中国工商银行",
        "中国农业银行",
        "中国银行",
        "中国建设银行",
        "交通银行",
        "中信银行",
        "中国光大银行",
        "华夏银行",
        "中国民生银行",
        "广发银行",
        "招商银行",
        "兴业银行",
        "浦发银行",
        "平安银行",
        "浙商银行",
        "渤海银行",
        "恒丰银行"
    ]

    # 尝试提取主要银行名称
    main_bank = ""
    for bank in main_banks:
        if bank in bank_name:
            main_bank = bank
            break

    # 如果没找到主要银行名称，使用原始名称的前部分
    if not main_bank and len(bank_name) > 2:
        # 找到第一个包含"银行"的部分
        if "银行" in bank_name:
            parts = bank_name.split("银行")
            if parts and len(parts) > 0:
                main_bank = parts[0] + "银行"

    # 提取分支机构名称（通常包含"分行"、"支行"等）
    branch = ""
    for branch_keyword in ["分行", "支行", "营业部", "分理处", "储蓄所"]:
        if branch_keyword in bank_name:
            # 提取包含关键词的后部分
            idx = bank_name.find(branch_keyword)
            if idx >= 0:
                # 向前查找一些字符作为分支名称
                start_idx = max(0, idx - 8)  # 最多往前找8个字符
                branch = bank_name[start_idx:idx + len(branch_keyword)]
                break

    # 组合标准化后的名称
    normalized = ""
    if main_bank:
        normalized += main_bank
    if branch:
        normalized += branch

    # 如果标准化后为空，返回原始名称
    if not normalized:
        return bank_name

    return normalized


def is_valid_account_number(account_number):
    """
    验证账号是否符合银行账号格式
    参数：
        account_number: 待验证的账号字符串
    返回：
        bool: 是否是有效账号
    """
    # 检查是否为空或None
    if not account_number:
        return False

    # 检查长度（中国银行账号通常为16-19位）
    if len(account_number) < 10:
        return False

    # 检查是否只包含数字
    if not account_number.isdigit():
        return False

    return True


def split_pdf_pages(pdf_path, output_dir=None):
    """
    将PDF文件按页面拆分为单独的PDF文件
    参数：
        pdf_path: 原始PDF文件路径
        output_dir: 输出目录，如果为None则使用原文件所在目录
    返回：
        List[str]: 拆分后的PDF文件路径列表
    """
    if not PDF_LIBRARY_AVAILABLE:
        logger.error("PDF处理库未安装，无法进行页面拆分")
        return [pdf_path]  # 返回原文件路径

    if not os.path.exists(pdf_path):
        logger.error(f"PDF文件不存在: {pdf_path}")
        return []

    # 确定输出目录
    if output_dir is None:
        output_dir = os.path.dirname(pdf_path)

    # 确保输出目录存在
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 获取原文件名（不含扩展名）
    base_name = os.path.splitext(os.path.basename(pdf_path))[0]

    split_files = []

    try:
        # # 优先使用PyMuPDF (fitz)
        # if 'fitz' in globals():
        #     logger.info(f"使用PyMuPDF拆分PDF: {pdf_path}")
        #     doc = fitz.open(pdf_path)
        #     total_pages = len(doc)
        #
        #     logger.info(f"PDF共有 {total_pages} 页，开始拆分...")
        #
        #     for page_num in range(total_pages):
        #         # 创建新的PDF文档
        #         new_doc = fitz.open()
        #         new_doc.insert_pdf(doc, from_page=page_num, to_page=page_num)
        #
        #         # 生成输出文件名
        #         output_filename = f"{base_name}_page-{page_num + 1:04d}.pdf"
        #         output_path = os.path.join(output_dir, output_filename)
        #
        #         # 保存单页PDF
        #         new_doc.save(output_path)
        #         new_doc.close()
        #
        #         split_files.append(output_path)
        #         logger.info(f"已保存第 {page_num + 1} 页: {output_filename}")
        #
        #     doc.close()

        # 备用方案：使用PyPDF2
        # el
        if 'PdfReader' in globals():
            logger.info(f"使用PyPDF2拆分PDF: {pdf_path}")
            with open(pdf_path, 'rb') as file:
                reader = PdfReader(file)
                total_pages = len(reader.pages)

                logger.info(f"PDF共有 {total_pages} 页，开始拆分...")

                for page_num in range(total_pages):
                    writer = PdfWriter()
                    writer.add_page(reader.pages[page_num])

                    # 生成输出文件名
                    output_filename = f"{base_name}_page-{page_num + 1:04d}.pdf"
                    output_path = os.path.join(output_dir, output_filename)

                    # 保存单页PDF
                    with open(output_path, 'wb') as output_file:
                        writer.write(output_file)

                    split_files.append(output_path)
                    logger.info(f"已保存第 {page_num + 1} 页: {output_filename}")

        else:
            logger.error("没有可用的PDF处理库")
            return [pdf_path]

        logger.info(f"PDF拆分完成，共生成 {len(split_files)} 个文件")
        return split_files

    except Exception as e:
        logger.error(f"拆分PDF时出错: {str(e)}", exc_info=True)
        return [pdf_path]  # 出错时返回原文件路径


def is_single_page_pdf(pdf_path):
    """
    检查PDF是否只有一页
    参数：
        pdf_path: PDF文件路径
    返回：
        bool: 是否为单页PDF
    """
    if not PDF_LIBRARY_AVAILABLE:
        return True  # 如果没有PDF库，假设是单页

    try:
        # if 'fitz' in globals():
        #     doc = fitz.open(pdf_path)
        #     page_count = len(doc)
        #     doc.close()
        #     return page_count == 1
        # el
        if 'PdfReader' in globals():
            with open(pdf_path, 'rb') as file:
                reader = PdfReader(file)
                return len(reader.pages) == 1
        else:
            return True
    except Exception as e:
        logger.warning(f"检查PDF页数时出错: {str(e)}")
        return True  # 出错时假设是单页


def process_all_files():
    """
    处理'清单'目录下的所有PDF和JPG文件，支持递归遍历子目录，自动页面拆分，每页单独调用OCR接口
    返回：所有文件的OCR结果合并列表
    """
    import shutil

    table_datas = []

    # 获取清单目录路径
    base_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "2025年二季度人行清单")

    # 创建拆分页面的临时目录
    temp_pages_dir = os.path.join(base_dir, "temp_pages")
    if not os.path.exists(temp_pages_dir):
        os.makedirs(temp_pages_dir)

    # 创建无法提取数据的文件存放目录
    failed_files_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "无法提取数据的文件")
    if not os.path.exists(failed_files_dir):
        os.makedirs(failed_files_dir)

    # 确保目录存在
    if not os.path.exists(base_dir):
        logger.error(f"错误：清单目录不存在 ({base_dir})")
        return table_datas

    # 递归遍历目录下所有PDF和JPG文件
    supported_files = []
    for root, dirs, files in os.walk(base_dir):
        # 跳过临时目录
        if "temp_pages" in root:
            continue

        for file in files:
            if file.lower().endswith(('.pdf', '.jpg', '.jpeg', '.png')):
                file_path = os.path.join(root, file)
                relative_path = os.path.relpath(file_path, base_dir)
                supported_files.append((file_path, relative_path))

    logger.info(f"发现 {len(supported_files)} 个支持的文件待处理（PDF/JPG/JPEG/PNG）")

    for file_path, relative_path in supported_files:
        file_name = os.path.basename(file_path)
        logger.info(f"处理文件: {relative_path}")

        try:
            file_has_data = False  # 标记文件是否成功提取到数据

            # 根据文件类型进行不同处理
            if file_path.lower().endswith('.pdf'):
                # PDF文件处理
                # 检查是否为单页PDF
                if is_single_page_pdf(file_path):
                    logger.info(f"{file_name} 是单页PDF，直接处理")
                    page_files = [file_path]
                else:
                    logger.info(f"{file_name} 是多页PDF，开始拆分页面")
                    # 拆分PDF页面
                    page_files = split_pdf_pages(file_path, temp_pages_dir)
                    logger.info(f"PDF拆分完成，共 {len(page_files)} 页")

                # 处理每个页面
                for page_idx, page_path in enumerate(page_files):
                    page_name = os.path.basename(page_path)
                    logger.info(f"  处理第 {page_idx + 1} 页: {page_name}")

                    try:
                        # 调用OCR接口处理单页PDF
                        tables = OCR(page_path)
                        if tables:
                            for table in tables:
                                if table:
                                    # 创建处理器
                                    processor = HTMLTableProcessor()

                                    # 处理HTML表格数据
                                    table_data = processor.extract_table_from_html(table)
                                    if table_data:  # 确保table_data不为空
                                        # 为每条记录添加来源信息
                                        for record in table_data:
                                            record['来源文件'] = relative_path
                                            record['来源页面'] = page_name
                                        table_datas.extend(table_data)
                                        logger.info(f"    从 {page_name} 提取到 {len(table_data)} 条记录")
                                        file_has_data = True
                        else:
                            logger.warning(f"    {page_name} OCR未返回数据")

                    except Exception as e:
                        logger.error(f"    处理页面 {page_name} 时出错: {str(e)}", exc_info=True)

            else:
                # 图片文件处理（JPG, JPEG, PNG）
                logger.info(f"{file_name} 是图片文件，直接处理")

                try:
                    # 调用OCR接口处理图片
                    tables = OCR(file_path)
                    if tables:
                        for table in tables:
                            if table:
                                # 创建处理器
                                processor = HTMLTableProcessor()

                                # 处理HTML表格数据
                                table_data = processor.extract_table_from_html(table)
                                if table_data:  # 确保table_data不为空
                                    # 为每条记录添加来源信息
                                    for record in table_data:
                                        record['来源文件'] = relative_path
                                        record['来源页面'] = file_name
                                    table_datas.extend(table_data)
                                    logger.info(f"    从 {file_name} 提取到 {len(table_data)} 条记录")
                                    file_has_data = True
                    else:
                        logger.warning(f"    {file_name} OCR未返回数据")

                except Exception as e:
                    logger.error(f"    处理图片 {file_name} 时出错: {str(e)}", exc_info=True)

            # 如果文件没有成功提取到数据，复制到失败文件夹
            if not file_has_data:
                try:
                    # 保持原有的目录结构
                    relative_dir = os.path.dirname(relative_path)
                    target_dir = os.path.join(failed_files_dir, relative_dir) if relative_dir else failed_files_dir

                    if not os.path.exists(target_dir):
                        os.makedirs(target_dir)

                    target_path = os.path.join(target_dir, file_name)
                    shutil.copy2(file_path, target_path)
                    logger.info(
                        f"    文件 {relative_path} 无法提取数据，已复制到: {os.path.relpath(target_path, os.path.dirname(os.path.abspath(__file__)))}")

                except Exception as copy_error:
                    logger.error(f"    复制失败文件时出错: {str(copy_error)}")

        except Exception as e:
            logger.error(f"处理 {relative_path} 时出错: {str(e)}", exc_info=True)

            # 处理出错的文件也复制到失败文件夹
            try:
                relative_dir = os.path.dirname(relative_path)
                target_dir = os.path.join(failed_files_dir, relative_dir) if relative_dir else failed_files_dir

                if not os.path.exists(target_dir):
                    os.makedirs(target_dir)

                target_path = os.path.join(target_dir, file_name)
                shutil.copy2(file_path, target_path)
                logger.info(
                    f"    处理出错的文件 {relative_path} 已复制到: {os.path.relpath(target_path, os.path.dirname(os.path.abspath(__file__)))}")

            except Exception as copy_error:
                logger.error(f"    复制出错文件时出错: {str(copy_error)}")

    # 清理临时文件（可选）
    try:
        # 删除临时拆分的页面文件，但保留原本就存在的单页文件
        if os.path.exists(temp_pages_dir):
            temp_files = os.listdir(temp_pages_dir)
            for temp_file in temp_files:
                temp_path = os.path.join(temp_pages_dir, temp_file)
                os.remove(temp_path)
                logger.debug(f"已删除临时文件: {temp_file}")
            os.rmdir(temp_pages_dir)
            logger.info("已清理临时拆分文件")
    except Exception as e:
        logger.warning(f"清理临时文件时出错: {str(e)}")

    logger.info(f"所有文件处理完成，共提取到 {len(table_datas)} 条记录")
    logger.info(
        f"无法提取数据的文件已保存到: {os.path.relpath(failed_files_dir, os.path.dirname(os.path.abspath(__file__)))}")
    return table_datas


def read_excel_data():
    """
    读取download目录下的'账户信息查询.xlsx'文件
    返回：DataFrame包含账户信息
    """
    # 获取Excel文件路径
    excel_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "download", "账户信息查询.xlsx")

    if not os.path.exists(excel_path):
        logger.error(f"错误：Excel文件不存在 ({excel_path})")
        return None

    try:
        # 读取Excel文件
        df = pd.read_excel(excel_path)
        logger.info(f"成功读取Excel文件，包含 {len(df)} 行数据")
        return df
    except Exception as e:
        logger.error(f"读取Excel文件时出错: {str(e)}", exc_info=True)
        return None


def compare_and_report_differences(ocr_data, excel_df):
    """
    比较OCR数据和Excel数据的差异
    参数：
        ocr_data: OCR处理后的数据列表，每项是一个字典
        excel_df: Excel读取的DataFrame
    返回:
        差异记录列表
    """
    if not ocr_data or excel_df is None or len(excel_df) == 0:
        logger.warning("没有足够的数据进行比较")
        return []

    # 清理Excel数据中的账号列，确保是字符串格式
    excel_df['账号'] = excel_df['账号'].astype(str).str.replace(r'\.0$', '', regex=True)
    logger.info("已标准化Excel数据中的账号格式")

    # 字段映射（OCR字段名 -> Excel字段名）
    field_mapping = {
        "账号": "账号",
        "开户银行名称": "开户银行名称",
        "账户性质": "账户性质",
        "开户日期": "开户日期",
        "账户状态": "使用状态",
        "销户日期": "销户日期"
    }

    # Excel字段列索引
    excel_column_indices = {
        "账号": "C",
        "账户名称": "D",
        "账户性质": "E",
        "开户银行名称": "I",
        "开户日期": "W",
        "使用状态": "T",
        "销户日期": "X"
    }

    # 账户性质映射关系
    account_type_mapping = {
        "基本存款账户": "基本账户",
        "基本账户": "基本账户",
        "一般存款账户": "一般账户",
        "一般账户": "一般账户",
        "专用存款账户": "专用账户",
        "专用账户": "专用账户",
        "非预算单位专用存款账": "专用账户",  # 处理可能的截断情况
        "临时存款账户": "临时账户",
        "临时账户": "临时账户"
    }

    # 记录差异
    differences = []

    # 处理OCR数据中的每一条记录
    logger.info(f"开始比较 {len(ocr_data)} 条OCR记录与Excel数据")

    for ocr_record in ocr_data:
        # 获取账号
        account_number = ocr_record.get("账号", "")
        if not account_number:
            continue

        # 确保账号是字符串类型
        account_number = str(account_number).strip()

        # 在Excel中查找匹配的记录
        matching_rows = excel_df[excel_df["账号"] == account_number]

        # 如果找到匹配的记录
        if len(matching_rows) > 0:
            excel_record = matching_rows.iloc[0]

            # 检查各字段差异
            record_diffs = []
            for ocr_field, excel_field in field_mapping.items():
                if ocr_field in ocr_record and excel_field in excel_record:
                    ocr_value = ocr_record[ocr_field]
                    excel_value = str(excel_record[excel_field])

                    # 处理账户性质映射
                    if ocr_field == "账户性质":
                        ocr_normalized = account_type_mapping.get(ocr_value, ocr_value)
                        excel_normalized = account_type_mapping.get(excel_value, excel_value)

                        if ocr_normalized == excel_normalized:
                            continue

                    # 处理银行名称标准化
                    if ocr_field == "开户银行名称":
                        ocr_normalized = normalize_bank_name(ocr_value)
                        excel_normalized = normalize_bank_name(excel_value)

                        logger.debug(
                            f"银行名称标准化: OCR '{ocr_value}' -> '{ocr_normalized}', Excel '{excel_value}' -> '{excel_normalized}'")

                        if ocr_normalized == excel_normalized:
                            continue

                    # 处理日期格式差异
                    if "日期" in ocr_field and excel_value:
                        try:
                            # 尝试将Excel日期转换为标准格式
                            # 首先检查是否已经是文本形式的日期
                            if "年" not in excel_value and "月" not in excel_value and "日" not in excel_value:
                                # 假设是datetime或其他格式，尝试转换
                                import re
                                from datetime import datetime

                                # 尝试多种可能的日期格式
                                date_formats = [
                                    "%Y-%m-%d %H:%M:%S",  # 处理带时间的格式，如"2022-06-29 00:00:00"
                                    "%Y-%m-%d",
                                    "%Y/%m/%d",
                                    "%Y.%m.%d",
                                    "%Y%m%d"
                                ]

                                # 如果包含时间部分，先尝试提取日期部分
                                if " " in excel_value:
                                    date_part = excel_value.split(" ")[0]
                                    try:
                                        parsed_date = datetime.strptime(date_part, "%Y-%m-%d")
                                        excel_value = f"{parsed_date.year}年{parsed_date.month:02d}月{parsed_date.day:02d}日"
                                        continue  # 已经成功转换，跳过下面的处理
                                    except ValueError:
                                        pass  # 如果失败，继续使用完整的日期时间字符串

                                # 清理日期字符串，移除非数字和常见分隔符
                                clean_date = re.sub(r'[^0-9\-\/\. :]', '', excel_value)

                                parsed_date = None
                                for fmt in date_formats:
                                    try:
                                        parsed_date = datetime.strptime(clean_date, fmt)
                                        break
                                    except ValueError:
                                        continue

                                if parsed_date:
                                    excel_value = f"{parsed_date.year}年{parsed_date.month:02d}月{parsed_date.day:02d}日"
                        except Exception as e:
                            logger.warning(f"处理日期时出错 ({excel_value}): {str(e)}")

                    # 处理状态字段映射（如"正常"对应"正常使用"等）
                    if ocr_field == "账户状态":
                        if ocr_value == "正常" and excel_value == "正常使用":
                            continue
                        if ocr_value == "撤销" and excel_value == "撤销":
                            continue

                    # 如果值不同，记录差异
                    if ocr_value != excel_value and ocr_value and excel_value:
                        record_diffs.append({
                            "字段": ocr_field,
                            "OCR值": ocr_value,
                            "Excel值": excel_value,
                            "Excel列": excel_column_indices.get(excel_field, "")
                        })

            # 如果有差异，添加到结果中
            if record_diffs:
                differences.append({
                    "账号": account_number,
                    "差异": record_diffs
                })
                logger.info(f"账号 {account_number} 存在 {len(record_diffs)} 处字段差异")
        else:
            # 如果在Excel中找不到匹配记录
            differences.append({
                "账号": account_number,
                "差异": "Excel中未找到此账号"
            })
            logger.info(f"账号 {account_number} 在Excel中未找到")

    # 输出差异报告
    if differences:
        logger.info(f"\n=== 差异报告 ===\n发现 {len(differences)} 条记录存在差异")
        for diff in differences:
            logger.info(f"\n账号: {diff['账号']}")
            if isinstance(diff['差异'], str):
                logger.info(f"  {diff['差异']}")
            else:
                for field_diff in diff['差异']:
                    logger.info(f"  字段: {field_diff['字段']} (Excel列: {field_diff['Excel列']})")
                    logger.info(f"    OCR值: {field_diff['OCR值']}")
                    logger.info(f"    Excel值: {field_diff['Excel值']}")
    else:
        logger.info("\n未发现差异")

    return differences


def save_ocr_results_to_excel(ocr_data):
    """
    将OCR识别结果保存为Excel表格，支持页面分割功能
    参数:
        ocr_data: OCR处理后的数据列表，每项是一个字典
    """
    if not ocr_data:
        logger.warning("没有OCR数据可保存")
        return

    try:
        # 如果启用页面分割功能，需要重新组织数据
        if Config.is_page_separator_enabled():
            organized_data = []
            current_file = None
            current_page = None

            for record in ocr_data:
                file_name = record.get('来源文件', '')
                page_name = record.get('来源页面', '')

                # 检查是否需要添加分割行
                if file_name != current_file or page_name != current_page:
                    if organized_data:  # 不是第一条记录时才添加分割行
                        # 添加空行作为分割
                        separator_row = {}
                        for key in record.keys():
                            if key not in ['来源文件', '来源页面']:
                                separator_row[key] = ""
                        separator_row['来源文件'] = ""
                        separator_row['来源页面'] = ""
                        organized_data.append(separator_row)

                    # 添加页面信息行
                    page_info_row = {}
                    for key in record.keys():
                        if key == '账号':
                            page_info_row[key] = Config.get_page_separator(file_name, page_name)
                        elif key not in ['来源文件', '来源页面']:
                            page_info_row[key] = ""
                        else:
                            page_info_row[key] = ""
                    organized_data.append(page_info_row)

                    current_file = file_name
                    current_page = page_name

                # 添加实际数据记录
                organized_data.append(record)

            # 创建DataFrame
            df = pd.DataFrame(organized_data)
        else:
            # 不启用页面分割功能时，直接创建DataFrame
            df = pd.DataFrame(ocr_data)

        # 确定输出路径
        output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), Config.RESULT_DIR_NAME)
        # 确保目录存在
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        # 保存为Excel文件
        output_path = os.path.join(output_dir, Config.OCR_RESULT_FILENAME)
        df.to_excel(output_path, index=False)
        logger.info(f"OCR识别结果已保存至: {output_path}")
        if Config.is_page_separator_enabled():
            logger.info("已启用页面分割功能，结果中包含页面分割信息")
    except Exception as e:
        logger.error(f"保存OCR结果时出错: {str(e)}", exc_info=True)


def save_differences_to_excel(differences, ocr_data=None, excel_df=None):
    """
    将差异结果保存为Excel表格，显示所有字段信息，支持页面分割功能
    参数:
        differences: 差异记录列表
        ocr_data: OCR数据列表，用于获取完整字段信息
        excel_df: Excel数据DataFrame，用于获取完整字段信息
    """
    if not differences:
        logger.warning("没有差异数据可保存")
        return

    try:
        # 字段映射（OCR字段名 -> Excel字段名）
        field_mapping = {
            "账号": "账号",
            "开户银行名称": "开户银行名称",
            "账户性质": "账户性质",
            "开户日期": "开户日期",
            "账户状态": "使用状态",
            "销户日期": "销户日期"
        }

        # 准备数据 - 每行显示一个完整的账户记录，最后几列显示差异信息
        rows = []

        # 如果启用页面分割功能，需要按页面组织数据
        if Config.is_page_separator_enabled() and ocr_data:
            # 按页面分组差异数据
            page_groups = {}
            for diff in differences:
                account_number = diff["账号"]
                # 查找对应的OCR记录以获取页面信息
                ocr_record = next(
                    (record for record in ocr_data if str(record.get("账号", "")).strip() == account_number), None)

                if ocr_record:
                    file_name = ocr_record.get('来源文件', '未知文件')
                    page_name = ocr_record.get('来源页面', '未知页面')
                    page_key = f"{file_name}|{page_name}"

                    if page_key not in page_groups:
                        page_groups[page_key] = []
                    page_groups[page_key].append(diff)
                else:
                    # 如果找不到OCR记录，放到默认组
                    default_key = "未知文件|未知页面"
                    if default_key not in page_groups:
                        page_groups[default_key] = []
                    page_groups[default_key].append(diff)

            # 按页面组处理差异数据
            for page_key, page_diffs in page_groups.items():
                file_name, page_name = page_key.split('|', 1)

                # 添加页面分割行
                separator_row = {
                    "OCR_账号": Config.get_page_separator(file_name, page_name),
                    "OCR_开户银行名称": "",
                    "OCR_账户性质": "",
                    "OCR_开户日期": "",
                    "OCR_账户状态": "",
                    "OCR_销户日期": "",
                    "差异类型": "",
                    "差异字段": "",
                    "Excel对应值": "",
                    "Excel列": "",
                    "差异说明": ""
                }
                rows.append(separator_row)

                # 处理该页面的所有差异记录
                for diff in page_diffs:
                    processed_rows = _process_single_difference(diff, ocr_data, excel_df, field_mapping)
                    rows.extend(processed_rows)
        else:
            # 不启用页面分割功能时，直接处理所有差异
            for diff in differences:
                processed_rows = _process_single_difference(diff, ocr_data, excel_df, field_mapping)
                rows.extend(processed_rows)

        # 创建DataFrame
        df = pd.DataFrame(rows)

        # 确定输出路径
        output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), Config.RESULT_DIR_NAME)
        # 确保目录存在
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        # 保存为Excel文件
        output_path = os.path.join(output_dir, Config.DIFF_RESULT_FILENAME)
        df.to_excel(output_path, index=False)
        logger.info(f"差异分析结果已保存至: {output_path}")
        if Config.is_page_separator_enabled():
            logger.info("已启用页面分割功能，结果中包含页面分割信息")
    except Exception as e:
        logger.error(f"保存差异结果时出错: {str(e)}", exc_info=True)


def _process_single_difference(diff, ocr_data=None, excel_df=None, field_mapping=None):
    """
    处理单个差异记录，返回处理后的行数据
    参数:
        diff: 单个差异记录
        ocr_data: OCR数据列表
        excel_df: Excel数据DataFrame
        field_mapping: 字段映射关系
    返回:
        List[Dict]: 处理后的行数据列表
    """
    rows = []
    account_number = diff["账号"]

    if isinstance(diff["差异"], str):
        # 如果是"Excel中未找到此账号"类型的差异
        if ocr_data:
            # 查找对应的OCR记录
            ocr_record = next(
                (record for record in ocr_data if str(record.get("账号", "")).strip() == account_number), None)
            if ocr_record:
                # 创建一行完整记录，包含所有OCR字段和差异信息
                row = {}
                # 添加所有OCR字段
                for ocr_field in field_mapping.keys():
                    row[f"OCR_{ocr_field}"] = ocr_record.get(ocr_field, "")

                # 添加差异信息
                row["差异类型"] = diff["差异"]
                row["差异字段"] = "整个账号"
                row["Excel对应值"] = "未找到记录"
                row["Excel列"] = ""
                row["差异说明"] = "该账号在Excel中不存在"

                rows.append(row)
            else:
                # 如果找不到OCR记录，创建一个基本记录
                row = {
                    "OCR_账号": account_number,
                    "OCR_开户银行名称": "",
                    "OCR_账户性质": "",
                    "OCR_开户日期": "",
                    "OCR_账户状态": "",
                    "OCR_销户日期": "",
                    "差异类型": diff["差异"],
                    "差异字段": "",
                    "Excel对应值": "",
                    "Excel列": "",
                    "差异说明": "OCR记录异常"
                }
                rows.append(row)
        else:
            # 如果没有OCR数据，使用基本格式
            row = {
                "OCR_账号": account_number,
                "OCR_开户银行名称": "",
                "OCR_账户性质": "",
                "OCR_开户日期": "",
                "OCR_账户状态": "",
                "OCR_销户日期": "",
                "差异类型": diff["差异"],
                "差异字段": "",
                "Excel对应值": "",
                "Excel列": "",
                "差异说明": "数据不完整"
            }
            rows.append(row)
    else:
        # 如果是具体字段差异
        if ocr_data and excel_df is not None:
            # 查找对应的OCR记录
            ocr_record = next(
                (record for record in ocr_data if str(record.get("账号", "")).strip() == account_number), None)

            if ocr_record:
                # 创建一行完整记录
                row = {}
                # 添加所有OCR字段
                for ocr_field in field_mapping.keys():
                    row[f"OCR_{ocr_field}"] = ocr_record.get(ocr_field, "")

                # 收集所有差异信息
                diff_details = []
                excel_values = []
                excel_columns = []

                for field_diff in diff["差异"]:
                    diff_details.append(field_diff["字段"])
                    excel_values.append(f"{field_diff['字段']}:{field_diff['Excel值']}")
                    excel_columns.append(f"{field_diff['字段']}:{field_diff['Excel列']}")

                # 添加差异信息
                row["差异类型"] = "字段不一致"
                row["差异字段"] = "; ".join(diff_details)
                row["Excel对应值"] = "; ".join(excel_values)
                row["Excel列"] = "; ".join(excel_columns)
                row["差异说明"] = f"共{len(diff['差异'])}个字段存在差异"

                rows.append(row)
        else:
            # 如果没有完整数据，使用简化格式
            for field_diff in diff["差异"]:
                row = {
                    "OCR_账号": account_number,
                    "OCR_开户银行名称": "",
                    "OCR_账户性质": "",
                    "OCR_开户日期": "",
                    "OCR_账户状态": "",
                    "OCR_销户日期": "",
                    "差异类型": "字段不一致",
                    "差异字段": field_diff["字段"],
                    "Excel对应值": field_diff["Excel值"],
                    "Excel列": field_diff["Excel列"],
                    "差异说明": "数据不完整"
                }
                rows.append(row)

    return rows


def OCR(file_path):
    url = 'http://10.157.223.51:8888/cxfServerX/identifyTableFile'

    # 检查文件是否存在
    if not os.path.exists(file_path):
        print(f"错误：文件不存在 - {file_path}")
        return None

    # 准备文件
    with open(file_path, 'rb') as file:
        files = {'file': (os.path.basename(file_path), file)}

        # 设置请求头
        headers = {
            'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
            'Accept': 'application/json',
            'Host': '10.157.223.51:8888',
            'Connection': 'keep-alive'
        }

        payload = {
            'username': 'test',
            'typeId': '3004',
            'autoRotation': '1',  # 自动旋转
            'layout': '1',
            'nLanguage': '3',
            'inclineCorrect': '1',  # 倾斜校正
        }

        # 发送POST请求
        print(f"正在调用OCR服务识别文件: {file_path}")
        response = requests.post(url, headers=headers, files=files, data=payload)

        a = 1

    # # 检查响应状态
    # if response.status_code != 200:
    #     print(f"请求失败，状态码: {response.status_code}")
    #     print(f"响应内容: {response.text}")
    #     return None

    # 解析JSON响应
    try:
        # ocr = response.json().get('ocr')
        # simpleResult = ocr.get('simpleResult')
        info = response.json().get('info')
        result = info.get('result')  # 这个result是一个数组
        tables = []
        for res in result:
            tables.append(res.get('table'))
        return tables
    except json.JSONDecodeError:
        print(f"无法解析响应JSON: {response.text}")
        return None


def extract_table_headers(all_rows):
    """
    提取表头信息
    参数：
        all_rows: 所有表格行
    返回：
        tuple: (headers, header_row_index)
    """
    headers = []
    header_row_index = -1

    # 遍历前几行寻找表头
    for row_idx, row in enumerate(all_rows[:5]):
        cells = row.find_all(['td', 'th'])
        potential_headers = []

        for cell in cells:
            cell_text = extract_cell_text(cell)
            if cell_text:
                potential_headers.append(cell_text)

        # 如果这一行包含典型的表头关键词，认为是表头行
        header_keywords = ['顺序', '开户银行', '账号', '账户性质', '开户日期', '账户状态', '久悬日期', '销户日期']
        if any(keyword in ''.join(potential_headers) for keyword in header_keywords):
            headers = potential_headers
            header_row_index = row_idx
            logger.info(f"在第 {row_idx + 1} 行找到表头: {headers}")
            break

    # 如果没有找到明确的表头，使用默认表头
    if not headers:
        logger.warning("未找到明确的表头，使用默认表头")
        headers = ['顺序', '开户银行名称', '账号', '账户性质', '开户日期', '账户状态', '久悬日期', '销户日期']
        header_row_index = 0

    return headers, header_row_index


def extract_table_data_rows(all_rows, headers, header_row_index):
    """
    提取数据行
    参数：
        all_rows: 所有表格行
        headers: 表头列表
        header_row_index: 表头行索引
    返回：
        List[Dict]: 数据行列表
    """
    data_rows = []

    # 从表头行之后开始处理数据行
    for row_idx, row in enumerate(all_rows):
        # 跳过表头行及之前的行
        if row_idx <= header_row_index:
            continue

        cells = row.find_all(['td', 'th'])
        if not cells:
            continue

        # 跳过明显的非数据行
        row_text = ''.join([extract_cell_text(cell) for cell in cells])
        skip_keywords = ['顺序', '开户银行', '存款人名称', '基本存款账户开户许可证', '填表说明']
        if any(keyword in row_text for keyword in skip_keywords):
            logger.debug(f"跳过非数据行 {row_idx}: {row_text[:50]}...")
            continue

        # 提取行数据
        row_data = {}
        for col_idx, cell in enumerate(cells):
            if col_idx < len(headers):
                cell_text = extract_cell_text(cell)
                row_data[headers[col_idx]] = cell_text

        # 验证是否为有效数据行
        if is_valid_table_data_row(row_data):
            data_rows.append(row_data)
            logger.debug(f"添加数据行 {row_idx}: {row_data}")
        else:
            logger.debug(f"跳过无效数据行 {row_idx}: {row_data}")

    return data_rows


def extract_cell_text(cell):
    """
    提取单元格文本内容
    参数：
        cell: BeautifulSoup单元格对象
    返回：
        str: 清理后的文本内容
    """
    text_parts = []

    # 查找所有span标签中的文本
    spans = cell.find_all('span')
    if spans:
        for span in spans:
            span_text = span.get_text(strip=True)
            if span_text and span_text not in text_parts:
                text_parts.append(span_text)

    # 查找所有p标签中的文本（如果没有span标签）
    if not text_parts:
        paragraphs = cell.find_all('p')
        if paragraphs:
            for p in paragraphs:
                # 先尝试从p标签内的span获取文本
                p_spans = p.find_all('span')
                if p_spans:
                    for span in p_spans:
                        span_text = span.get_text(strip=True)
                        if span_text and span_text not in text_parts:
                            text_parts.append(span_text)
                else:
                    # 如果p标签内没有span，直接获取p标签文本
                    p_text = p.get_text(strip=True)
                    if p_text and p_text not in text_parts:
                        text_parts.append(p_text)

    # 如果还是没有文本，直接获取单元格文本
    if not text_parts:
        cell_text = cell.get_text(strip=True)
        if cell_text:
            text_parts.append(cell_text)

    # 合并文本内容，用空格连接
    combined_text = ' '.join(text_parts)

    # 清理文本
    cleaned_text = clean_cell_text(combined_text)

    return cleaned_text


def clean_cell_text(text):
    """
    清理文本内容
    参数：
        text: 原始文本
    返回：
        str: 清理后的文本
    """
    if not text:
        return ""

    # 移除特殊字符
    text = text.replace('&nbsp;', '').replace('\xa0', '')

    # 去除前后空白
    text = text.strip()

    # 移除多余的空白字符
    text = re.sub(r'\s+', ' ', text)

    return text


def is_valid_table_data_row(row_data):
    """
    验证是否为有效的数据行
    参数：
        row_data: 行数据字典
    返回：
        bool: 是否为有效数据行
    """
    # 检查是否有顺序字段且为数字
    sequence = row_data.get('顺序', '').strip()
    if sequence and sequence.isdigit():
        # 如果有顺序号，这很可能是数据行
        pass
    else:
        # 如果没有顺序号，检查其他关键字段
        account_number = row_data.get('账号', '').strip()
        if not account_number:
            return False

        # 检查账号是否包含数字（放宽验证条件）
        if not re.search(r'\d{10,}', account_number):
            return False

    # 检查是否有银行名称
    bank_name = row_data.get('开户银行名称', '').strip()
    if not bank_name or len(bank_name) < 3:
        return False

    # 检查是否包含明显的非数据内容
    all_text = ' '.join(row_data.values()).lower()
    invalid_keywords = ['填表说明', '存款人', '许可证', '核准号']
    if any(keyword in all_text for keyword in invalid_keywords):
        return False

    return True


def remove_spaces_from_table_data(data_rows):
    """
    对提取的数据进行去空格处理
    主要针对OCR识别可能产生的不连续文本问题
    参数：
        data_rows: 原始数据行列表
    返回：
        List[Dict]: 去空格后的数据行列表
    """
    cleaned_rows = []

    for row in data_rows:
        cleaned_row = {}
        for key, value in row.items():
            if not value:
                cleaned_row[key] = value
                continue

            # 根据字段类型进行不同的去空格处理
            if key == '账号':
                # 账号完全去除所有空格
                cleaned_value = re.sub(r'\s+', '', value)
            elif key in ['开户银行名称']:
                # 银行名称去除所有空格
                cleaned_value = re.sub(r'\s+', '', value)
            elif key in ['开户日期', '久悬日期', '销户日期']:
                # 日期去除所有空格
                cleaned_value = re.sub(r'\s+', '', value)
            elif key == '账户性质':
                # 账户性质去除所有空格
                cleaned_value = re.sub(r'\s+', '', value)
            elif key == '账户状态':
                # 账户状态去除所有空格
                cleaned_value = re.sub(r'\s+', '', value)
            else:
                # 其他字段保持原有的空格处理逻辑
                cleaned_value = re.sub(r'\s+', ' ', value).strip()

            cleaned_row[key] = cleaned_value

        cleaned_rows.append(cleaned_row)

    logger.info(f"完成数据去空格处理，处理了 {len(cleaned_rows)} 行数据")
    return cleaned_rows


def parse_html_table(html_content):
    """
    解析HTML表格数据，支持复杂的嵌套结构和自动去空格处理
    参数：
        html_content: HTML格式的表格内容
    返回：
        rows: 按行组织的数据列表，每行是一个字典
    """
    try:
        # 使用BeautifulSoup解析HTML
        soup = BeautifulSoup(html_content, 'html.parser')

        # 查找所有表格
        tables = soup.find_all('table')
        if not tables:
            logger.warning("HTML中未找到表格")
            return []

        # 处理第一个表格
        table = tables[0]
        all_rows = table.find_all('tr')

        if not all_rows:
            logger.warning("表格中未找到行数据")
            return []

        # 分析表格结构，找到表头和数据行
        headers, header_row_index = extract_table_headers(all_rows)
        data_rows = extract_table_data_rows(all_rows, headers, header_row_index)

        # 对提取的数据进行去空格处理
        cleaned_data_rows = remove_spaces_from_table_data(data_rows)

        logger.info(f"HTML表格解析完成，共 {len(cleaned_data_rows)} 条有效记录")
        return cleaned_data_rows

    except Exception as e:
        logger.error(f"解析HTML表格时出错: {str(e)}", exc_info=True)
        return []



if __name__ == '__main__':
    logger.info("=== 开始运行账户信息差异分析 ===")

    # 主流程
    # 1. 处理所有支持的文件（PDF和图片）
    logger.info("步骤1: 处理所有支持的文件并进行OCR识别（PDF/JPG/JPEG/PNG）")
    all_ocr_data = process_all_files()

    # 保存OCR识别结果到Excel
    if all_ocr_data:
        logger.info("步骤2: 保存OCR识别结果到Excel")
        save_ocr_results_to_excel(all_ocr_data)

    # 2. 读取Excel文件
    logger.info("步骤3: 读取账户信息Excel文件")
    excel_data = read_excel_data()

    # 3. 比较差异并输出报告
    if all_ocr_data and excel_data is not None:
        logger.info("步骤4: 比较OCR结果与Excel数据的差异")
        differences = compare_and_report_differences(all_ocr_data, excel_data)

        # 保存差异结果到Excel
        if differences:
            logger.info("步骤5: 保存差异分析结果到Excel")
            save_differences_to_excel(differences, all_ocr_data, excel_data)

    logger.info("=== 账户信息差异分析完成 ===")

    # OCR(r"C:\Users\86133\PycharmProjects\4人行清单OCR差异分析\清单\湖北_账户开立清单_page-0001.pdf")
    # 导出()
